-module(my_ping).
-export([init/3, start/4, stop/1]).

-spec start/4 :: (node(), atom(), atom(), list(atom())) -> pid().
start(Node, Name, ReportTo, ContactWith) ->
  pong = net_adm:ping(Node),
  P = spawn(Node, my_ping, init, [Name, ReportTo, ContactWith]),
  yes = global:register_name(Name, P),
  P.

init(Name, ReportTo, ContactWith) ->
  application:load(ssu2015DeviceTest),
  wait_for_me_registered(Name),
  case global:whereis_name(ReportTo) of
    undefined ->
      lists:foreach(fun(Atom) ->
        io:format("node ~p ", [Atom])
      end,
        nodes()),

      error(global:registered_names());

    Pid when is_pid(Pid) ->
      Pid ! {started, Name},
      receive
        start_loop -> ok
      end,
      event_loop(ContactWith, Name)
  end.

wait_for_me_registered(Name) ->
  case global:whereis_name(Name) of
    undefined ->
      io:format("not registered ~p~n", [Name]),
      timer:sleep(200),
      wait_for_me_registered(Name);

    Pid when is_pid(Pid) ->
      ok
  end.

stop(Name) ->
  case whereis(Name) of
    undefined -> ok;
    Pid when is_pid(Pid) ->
      Pid ! {stop, self()},
      receive
        {ok, Name} ->
          true
      after 1000 -> false
      end
  end.

-spec event_loop/2 :: (list(atom()), atom()) -> {ok, atom()}.
event_loop(ContactWith, MyName) ->
  ok = sendAll(ContactWith, MyName),
  ok = receiveAll(ContactWith),
  receive
    {stop, From} ->
      From ! {ok, MyName}
  after 500 ->
    event_loop(ContactWith, MyName)
  end.


receiveAll([]) -> ok;
receiveAll([Fst | Rest]) ->
  receive
    {alive, Fst} -> receiveAll(Rest)
  after 1000 ->
    {ok, ShouldDie} = application:get_env(shutdown_on_split),
    case ShouldDie of
      true ->
        Message = io_lib:format("netsplit on ~p with ~p", [node(), Fst]),
        error(Message);
      false ->
        io:format("too long on ~p from ~p~n", [node(), Fst]),
        receiveAll([Fst | Rest])
    end
  end.

sendAll(ListenersNames, Name) ->
  SendHim = fun(HisName) ->
    case global:whereis_name(HisName) of
      undefined ->
        Message = io_lib:format("netsplit on ~p with ~p", [node(), HisName]),
        error(Message);
      Pid when is_pid(Pid) ->
        Pid ! {alive, Name}
    end
  end,
  lists:foreach(SendHim, ListenersNames).